package com.timemetro.app;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.timemetro.app.stationObject.InfoNextStation;
import com.timemetro.app.stationObject.Station;
import com.timemetro.app.stationObject.StatusStation;
import com.timemetro.app.stationObject.TypeStation;

/**
 * Created by gabik on 29.05.15.
 */
public class ManagerStation {
    private static Logger log = Logger.getLogger(GraphCalculate.class.getName());

    private static Station currentStation = new Station();

    private static int indexBeginStation;
    private static Station beginStation;
    public static Station getBeginStation() {
        return beginStation;
    }
    public static int getIndexBeginStation() {
        if (nodeStations.contains(beginStation)){
            return nodeStations.indexOf(beginStation);
        }
        return indexBeginStation;
    }

    private static int indexEndStation;
    private static Station endStation;
    public static Station getEndStation() {
        return endStation;
    }
    public static int getIndexEndStation() {
        if (nodeStations.contains(endStation)){
            return nodeStations.indexOf(endStation);
        }
        return indexEndStation;
    }

    private static float currentTimeBetweenStation;
    public static Station getCurrentStation() {
        return currentStation;
    }

// Структура хранения всех станций метро.
    private static Map<Integer, List<Station>> allStations = new HashMap<Integer, List<Station>>();
    public static Map<Integer, List<Station>> getAllStations() {
        return allStations;
    }

// Структура хранения узловых станций метро. В данный массив попподают лишь узловые станции.
// Это необходимо для более быстрого подсчета маршрутов между станциями.
    private static List<Station> nodeStations = new ArrayList<Station>();

    /*Метод добавлени новой станции метро в массив всех станций и в масссив узловых станций*/
    public static void addStation(Station station){
//        Если станция узловая - добавляем в массив узловых, и устанавливаем зарезервированные индексы для начальной и конечных станций:
        try {
            if (station.getTypeStation() == TypeStation.NODE || station.getTypeStation() == TypeStation.NODE_RING) {
                nodeStations.add(station);
                indexBeginStation = nodeStations.size();    // Индекс начальной станции = индекс последнего узлового + 1;
                indexEndStation = nodeStations.size() + 1;    // Индекс конечной станции = индекс последнего узлового + 2;
            }

//        Кроме того, все станции добавляем в общий массив станций:
            int idBranch = (station).getIdBranch();
            if (allStations.containsKey(idBranch)) {
//            Если ветка с таким id уже создана, добавляем в неё новую станцию:
                (allStations.get(idBranch)).add(station);
            } else {
//            Иначе создаем новую ветку и добавляем в неё новую станцию:
                allStations.put(idBranch, new ArrayList<Station>());
                (allStations.get(idBranch)).add(station);
            }
        } catch (Exception ex){
            log.log(Level.SEVERE, "Ошибка при добавлении станции. Метод ddStation(Station station):", ex);
        }
    }

    public static void touchingScreen(float positionX, float positionY){
        for (List<Station> list : allStations.values())
            for (Station objectScene: list){
                if(objectScene.isTouch(positionX, positionY)){
                    currentStation = objectScene;
                    ManagerViewElements.showSelectStationPanel();
                }
            }
    }

    public static void setBeginStation(Station station) throws InterruptedException {
        if (beginStation == station){
            return;
        }
        if (beginStation != null){
            beginStation.setStatusStation(StatusStation.normal);
        } else {
            beginStation = new Station();
        }
        beginStation = station;
        beginStation.setStatusStation(StatusStation.beginStation);
        ActivationNewPath();
    }
    public static void setEndStation(Station station) throws InterruptedException {
        if (endStation == station){
            return;
        }
        if (endStation != null){
            endStation.setStatusStation(StatusStation.normal);
        } else {
            endStation = new Station();
        }
        endStation = station;
        endStation.setStatusStation(StatusStation.endStation);
        ActivationNewPath();
    }

    public static void ActivationNewPath() throws InterruptedException {
        if (beginStation == null || endStation == null) return;
        if (isBeginAndEndStationOneBranch()){
            ActivationStationOneBranch();
        } else {
            GraphCalculate.startCalculate();}
    }

    /*Активация станций одной ветки*/
    private static void ActivationStationOneBranch(){
        clearBranch();
        int idBranch = beginStation.getIdBranch();
        List<Station> stationOneBranchList = (ManagerStation.getAllStations()).get(idBranch);
        int startIndex = stationOneBranchList.indexOf(beginStation);
        int endIndex = stationOneBranchList.indexOf(endStation);
        if (startIndex > endIndex){
            int temp = startIndex;
            startIndex = endIndex;
            endIndex = temp;
        }
        for (int i = startIndex; i <= endIndex; i++){
            stationOneBranchList.get(i).setStatusStation(StatusStation.branchStation);
        }
    }

    private static boolean isBeginAndEndStationOneBranch(){
        if (beginStation.getIdBranch() == endStation.getIdBranch()) return true;
        return false;
    }
    public static void setActiveSeveralBranch(List<Integer> indexNodeStations)
    {
        clearBranch();
        for (Integer indexStation: indexNodeStations){
            getNodeBgnEndStationOnIndex(indexStation).setStatusStation(StatusStation.branchStation);
        }

/*        for (int i = 0; i < indexNodeStations.size()-1; i++){
            if (getTypeOfConnectionStation(getNodeBgnEndStationOnIndex(i),getNodeBgnEndStationOnIndex(i+1)) == TypeOfConnectionStation.NOT_NEIGHBORS){
                List<Station> currentBranch = allStations.get(nodeStations.get(i).getIdBranch());
            }
        }

        int countNodeStation = nodeStations.size();
        for (int i = 0; i < countNodeStation-1; i++){
            if (getTypeOfConnectionStation(nodeStations.get(i), nodeStations.get(i+1)) == TypeOfConnectionStation.NOT_NEIGHBORS || nodeStations.get(i+1) == endStation){
                List<Station> currentBranch = allStations.get(nodeStations.get(i).getIdBranch());
                int indexFirstStation = currentBranch.indexOf(nodeStations.get(i));
                int indexSecondStation = currentBranch.indexOf(nodeStations.get(i+1));
                int temp;
                if (indexFirstStation > indexSecondStation){
                    temp = indexFirstStation;
                    indexFirstStation = indexSecondStation;
                    indexSecondStation = temp;
                }
                for (int j = indexFirstStation; j <= indexSecondStation;j++){
                    currentBranch.get(j).setStatusStation(StatusStation.branchStation);
                }
            }
        }*/
    }

    private static Station getNodeBgnEndStationOnIndex(int index){
        if (index < nodeStations.size()) {
            return nodeStations.get(index);
        } else if (index == indexBeginStation){
            return beginStation;
        } else if (index == indexEndStation){
            return endStation;
        }
        log.fine("У функции getNodeBgnEndStationOnIndex(int index) нет элемента, соответствующего индексу: " + index);
        return null;
    }



/*    *//* Делаем активным путь одной ветки*//*
    public static void setActiveOneBranch(List<Integer> idStations, int idBranch)
    {
        clearBranch();
        for (Integer id: idStations){
            for (Station station: allStations.get(idBranch))
            {
                if (station.getIdStation() == id){
                    station.setStatusStation(StatusStation.branchStation);
                }
            }
        }
    }*/

    private static void clearBranch(){
        for (List<Station> list : allStations.values())
            for (Station objectScene: list){
                if(objectScene.getStatusStation() == StatusStation.branchStation){
                    objectScene.setStatusStation(StatusStation.normal);
                }
            }
    }
/*Получение id станции по индексу станции в наборе Узловых станций*/
    public static int getIdNodeBegEndStation(int index){
        if (index < nodeStations.size()) {
            return nodeStations.get(index).getIdStation();
        } else if (index == indexBeginStation){
            return beginStation.getIdStation();
        } else if (index == indexEndStation){
            return endStation.getIdStation();
        }
        log.fine("У функции getIdNodeStation(int index) нет элемента, соответствующего индексу: " + index);
        return -1;
    }

/*Получение имени станции по индексу станции в наборе Узловых станций*/
    public static String getNameNodeBegEndStation(int index){
        if (index == 31){
            int sd = 0;
        }
        if (index < nodeStations.size()) {
            return nodeStations.get(index).getName();
        } else if (index == indexBeginStation){
            return beginStation.getName();
        } else if (index == indexEndStation){
            return endStation.getName();
        }
        log.fine("У функции getNameNodeBegEndStation(int index) нет элемента, соответствующего индексу: " + index);
        return "";
    }

    public static boolean beginStationIsNode(){
        if (beginStation.getTypeStation() == TypeStation.NODE || beginStation.getTypeStation() == TypeStation.NODE_RING)
            return true;
        return false;
    }

    public static boolean endStationIsNode(){
        if (endStation.getTypeStation() == TypeStation.NODE || endStation.getTypeStation() == TypeStation.NODE_RING)
            return true;
        return false;
    }

    private static List<Station> getNodeStations(){
        List<Station> nodeStation = new ArrayList<Station>();
        for (List<Station> list : allStations.values())
            for (Station objectScene: list){
               if (objectScene.getTypeStation() == TypeStation.NODE || objectScene.getTypeStation() == TypeStation.NODE_RING)
               {
                   nodeStation.add(objectScene);
               }
            }
        return nodeStation;
    }

    public static int getCountNodeStations(){
        return nodeStations.size();
    }

    public static float getDistanceBetweenNodeStation(int indexFirstNodeStation, int indexSecondNodeStation) {
            Station stationOne = getNodeStationOnId(indexFirstNodeStation);
            Station stationTwo = getNodeStationOnId(indexSecondNodeStation);
            switch (getTypeOfConnectionStation(stationOne, stationTwo)){
                case NEIGHBORS_AND_IN_FIRST:
                    return stationOne.getTimeUntilNextStation();
                case NEIGHBORS_AND_IN_SECOND:
                    return stationTwo.getTimeUntilNextStation();
                case NOT_NEIGHBORS:
                    return GetDistanceBetweenStationsOneBranch(stationOne, stationTwo);
                case TWO_NODE:
                    return currentTimeBetweenStation;
                case NO_CONNECTION:
                default:
                    return Float.MAX_VALUE;  // Возвращаем бесконечно возможное значение;
            }
    }

    private static Station getNodeStationOnId(int indexNodeStation){
        return nodeStations.get(indexNodeStation);
    }

    private static boolean isStationBelongsOneBranch(int indexFirstNodeStation, int indexSecondNodeStation){
        if (nodeStations.get(indexFirstNodeStation).getIdBranch() ==
                nodeStations.get(indexSecondNodeStation).getIdBranch()){
            return true;
        }
        return false;
    }

/*Получение типа связи между станциями
* @param stationOne Первая станция для анализа
* @param stationTwo Вторая станция для анализа*/
    private static TypeOfConnectionStation getTypeOfConnectionStation(Station stationOne, Station stationTwo){
        int indexOne = (allStations.get(stationOne.getIdBranch())).indexOf(stationOne);
        int indexTwo = (allStations.get(stationOne.getIdBranch())).indexOf(stationTwo);
        if (indexOne == indexTwo) return TypeOfConnectionStation.NO_CONNECTION;
// ВАРИАНТЫ ДЛЯ СТАНЦИЙ ОДНОЙ ВЕТКИ
        if (stationOne.getIdBranch() == stationTwo.getIdBranch()) {
// Если станции являются соседними
            if (Math.abs(indexOne - indexTwo) == 1) {
                if (indexOne > indexTwo) {
                    return TypeOfConnectionStation.NEIGHBORS_AND_IN_FIRST;
                } else {
                    return TypeOfConnectionStation.NEIGHBORS_AND_IN_SECOND;
                }
// В кольцевой станции необходимо учитывать связь между последней и первой станцией
            } else if (stationOne.getTypeStation() == TypeStation.NODE_RING) {
                if (indexOne == 0 && indexTwo == 11) {
                    return TypeOfConnectionStation.NEIGHBORS_AND_IN_SECOND;
                } else if (indexOne == 11 && indexTwo == 0) {
                    return TypeOfConnectionStation.NEIGHBORS_AND_IN_FIRST;
                }
// Если узловые станции расположены на одной ветке, но между ними есть только не узловые станции:
            } else if (NodeStationIsNotNeighbors(stationOne, stationTwo)) {
                return TypeOfConnectionStation.NOT_NEIGHBORS;
            }
// ВАРИАНТЫ ДЛЯ СТАНЦИЙ РАЗНЫХ ВЕТОК
        } else
        {
            List<InfoNextStation> infoNextStations = stationOne.getInfoNextNodeList();
            for (InfoNextStation infoNextStation: infoNextStations)
            {
                if (infoNextStation.id == stationTwo.getIdStation()){
                    currentTimeBetweenStation = infoNextStation.length;
                    return TypeOfConnectionStation.TWO_NODE;
                }
            }
        }
        return TypeOfConnectionStation.NO_CONNECTION;
    }

    /* Проверка станция на нахождение между ними узловых станций
    * @param stationOne Начальная станция проверки
    * @param stationTwo Конечная станция проверки
    * @return Возвращается истина, если между станциями нет узловых*/
    private static boolean NodeStationIsNotNeighbors(Station stationOne, Station stationTwo){
        boolean nodeStationIsNotNeighbors = true;
        List<Station> stations = allStations.get(stationOne.getIdBranch());
        int indexOne = stations.indexOf(stationOne);
        int indexTwo = stations.indexOf(stationTwo);
        if (indexOne > indexTwo){
            int temp = indexOne;
            indexOne = indexTwo;
            indexTwo = temp;
        }
        for (int i = indexOne + 1; i < indexTwo; i++){
            if (stations.get(i).getTypeStation() == TypeStation.NODE){
                nodeStationIsNotNeighbors = false;
            }
        }
        return nodeStationIsNotNeighbors;
    }

    /*Получение протяженности между двумя станциями одной ветки*/
    private static float GetDistanceBetweenStationsOneBranch(Station beginStation, Station endStation){
        List<Station> stations = allStations.get(beginStation.getIdBranch());
        int indexOne = stations.indexOf(beginStation);
        int indexTwo = stations.indexOf(endStation);
        if (indexOne > indexTwo){
            int temp = indexOne;
            indexOne = indexTwo;
            indexTwo = temp;
        }
        float lengthPath = 0;
        for (int i = indexOne; i < indexTwo; i++){
            lengthPath += (stations.get(i)).getTimeUntilNextStation();
        }
        return lengthPath;
    }

    public static List<InfoNextStation> getNeighborsNodes(Station station){
        List<Station> stationList = allStations.get(station.getIdBranch());
        int indexStation = stationList.indexOf(station);
        List<InfoNextStation> infoNextStationList = new ArrayList<InfoNextStation>();
        float time = 0;
        for (int i = indexStation; i < stationList.size();i++){
            if (stationList.get(i).getTypeStation() == TypeStation.NODE || stationList.get(i).getTypeStation() == TypeStation.NODE_RING){
                infoNextStationList.add(new InfoNextStation(stationList.get(i).getIdStation(), time));
                break;
            }
            time += stationList.get(i).getTimeUntilNextStation();
        }
        time = 0;
        for (int i = indexStation; i >= 0;i--){
            if (stationList.get(i).getTypeStation() == TypeStation.NODE || stationList.get(i).getTypeStation() == TypeStation.NODE_RING){
                infoNextStationList.add(new InfoNextStation(stationList.get(i).getIdStation(), time));
                break;
            }
            if (i > 0) time += stationList.get(i-1).getTimeUntilNextStation();
        }
        return infoNextStationList;
    }

    /*Тип связи между станциями одной ветки*/
    enum TypeOfConnectionStation{
        NO_CONNECTION,                       // Между станциями нет связи;
        NEIGHBORS_AND_IN_FIRST,              // Станции соседи на одной ветке и путь между станциями находится в первой станции;
        NEIGHBORS_AND_IN_SECOND,             // Станции соседи на одной ветке и путь между станциям находится во второй станции;
        NOT_NEIGHBORS,                       // Станции не соседи на одной ветке, между ними есть не узловые станции;
        TWO_NODE                             // Переход между ветками.
    }
}
